﻿// <copyright file="WebAnalyticsService.cs" company="Microsoft Corporation">
// Copyright (c) 2009 Microsoft Corporation All Rights Reserved
// </copyright>
// <author>Michael S. Scherotter</author>
// <email>mischero@microsoft.com</email>
// <date>2009-10-08</date>
// <summary>WebAnalytics Service class definition</summary>

namespace Microsoft.WebAnalytics
{
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel.Composition;
    using System.Diagnostics.CodeAnalysis;
    using System.IO.IsolatedStorage;
    using System.Net.NetworkInformation;
    using System.Windows;
    using System.Windows.Interactivity;
    using Microsoft.WebAnalytics.Contracts;

    /// <summary>
    /// Web Analytics Service for Silverlight Applications
    /// </summary>
    public class WebAnalyticsService : IApplicationService, IApplicationLifetimeAware
    {
        #region Fields

        /// <summary>
        /// The default layoutRoot name for the 
        /// </summary>
        private const string DefaultLayoutRootName = "LayoutRoot";

        /// <summary>
        /// true if the service behaviors have been added to the LayoutRoot element
        /// </summary>
        private bool behaviorsAdded;
        #endregion

        /// <summary>
        /// Initializes a new instance of the WebAnalyticsService class.
        /// </summary>
        public WebAnalyticsService()
        {
            this.LayoutRootName = DefaultLayoutRootName;

            this.Services = new Collection<System.Windows.Interactivity.Behavior>();
        }
        
        /// <summary>
        /// Gets or sets the name of the root visual panel (Typically LayoutRoot)
        /// </summary>
        /// <remarks>You set the LayoutRootName when you want to specify the 
        /// element to add the service behaviors to when they are declared in 
        /// the Services collection.</remarks>
        public string LayoutRootName { get; set; }

        #region Properties

        /// <summary>
        /// Gets or sets the service behaviors
        /// </summary>
        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Necessary for XAML serialization.")]
        public Collection<System.Windows.Interactivity.Behavior> Services { get; set; }

        /// <summary>
        /// Gets or sets the event log
        /// </summary>
        [Import]
        public EventLog EventLog { get; set; }

        /// <summary>
        /// Gets or sets the data collector
        /// </summary>
        [Import]
        public IDataCollector DataCollector { get; set; }

        /// <summary>
        /// Gets or sets the events that each dispatcher can hook into
        /// </summary>
        [Import]
        public WebAnalyticsEvents Events { get; set; }

        #endregion

        #region Methods
        /// <summary>
        /// When service behaviors are defined in the WebAnalyticsService.Services collection, they need to be
        /// added to the scene
        /// </summary>
        public void AttachServices()
        {
            if (this.behaviorsAdded)
            {
                return;
            }

            if (this.Services.Count == 0)
            {
                return;
            }

            var root = Application.Current.RootVisual as FrameworkElement;

            System.Diagnostics.Debug.Assert(root != null, "Cannot add WebAnalytics Services to Application.RootVisual because it is not a FrameworkElement.");

            System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(this.LayoutRootName), "Cannot add WebAnalytics Services to Application.RootVisual LayoutRootName is null or empty.");

            var layoutRoot = root.FindName(this.LayoutRootName) as DependencyObject;

            System.Diagnostics.Debug.Assert(layoutRoot != null, "Cannot add WebAnalytics Services to Application", "element {0} could not be found.", this.LayoutRootName);

            this.AttachServices(layoutRoot);
        }

        /// <summary>
        /// Attach service behaviors to the scene
        /// </summary>
        /// <param name="layoutRoot">the layoutRoot element</param>
        public void AttachServices(DependencyObject layoutRoot)
        {
            if (this.behaviorsAdded)
            {
                return;
            }

            var behaviors = Interaction.GetBehaviors(layoutRoot);

            foreach (var behavior in this.Services)
            {
                behaviors.Add(behavior);
            }

            this.behaviorsAdded = true;
        }

        #endregion

        #region IApplicationService Members

        /// <summary>
        /// Service is starting
        /// </summary>
        /// <param name="context">the application service context</param>
        public void StartService(ApplicationServiceContext context)
        {
#if WINDOWS_PHONE
            CompositionInitializerEx.SatisfyImports(this);
#else
            PartInitializer.SatisfyImports(this);
#endif
            if (context != null)
            {
                this.DataCollector.Initialize(context.ApplicationInitParams);
            }
        }

        /// <summary>
        /// Service has stopped, so write the event log
        /// </summary>
        public void StopService()
        {
            try
            {
                this.EventLog.WriteLog();
            }
            catch (IsolatedStorageException ise)
            {
                System.Diagnostics.Debug.WriteLine(ise.Message);
            }
        }

        #endregion

        #region IApplicationLifetimeAware Members

        /// <summary>
        /// Service has exited
        /// </summary>
        public void Exited()
        {
            var logEvent = new AnalyticsEvent()
            {
                Name = "Exited",
                ObjectName = "WebAnalyticsService"
            };

            this.DataCollector.Log(logEvent);
        }

        /// <summary>
        /// Service is exiting
        /// </summary>
        public void Exiting()
        {
            var logEvent = new AnalyticsEvent()
            {
                Name = "Exiting",
                ObjectName = "WebAnalyticsService"
            };

            this.DataCollector.Log(logEvent);
        }

        /// <summary>
        /// Service has started
        /// </summary>
        public void Started()
        {
            this.AttachServices();

            var logEvent = new AnalyticsEvent()
            {
                Name = "Started",
                ObjectName = "WebAnalyticsService"
            };

            this.DataCollector.Log(logEvent);
        }

        /// <summary>
        /// Service is starting
        /// </summary>
        public void Starting()
        {
            var logEvent = new AnalyticsEvent()
            {
                Name = "Starting",
                ObjectName = "WebAnalyticsService"
            };

            this.DataCollector.Log(logEvent);
        }

        #endregion
    }
}
